(define nil ())
(null? nil)

(define (fold-left op initial sequence)
  (define (iter result rest)
    (if (null? rest)
        result
        (iter (op result (car rest))
              (cdr rest))))
  (iter initial sequence))
(fold-left / 1 (list 1 2 3))
(fold-left list nil (list 1 2 3))
(define lst (list 1 2 3 4))
;accumulate
(define (accumulate op initial sequence)
  (if (null? sequence)
      initial
      (op (car sequence)
          (accumulate op initial (cdr sequence)))))
(accumulate + 0 lst)
(accumulate * 1 lst)
(RESTART 1)
(define fold-right accumulate)
(fold-right / 1 (list 1 2 3))
(fold-right list nil (list 1 2 3))

(define (reverse-fold-right sequence)
  (fold-right (lambda (x y) (append y (list x)))
              nil sequence))
(reverse-fold-right lst)
n
(define (reverse-fold-left sequence)
  (fold-left (lambda (x y) (cons y x)) nil sequence))
(reverse-fold-left lst)

(reverse lst)

(define (enumerate-interval i j)
  (if (> i j) nil (cons i (enumerate-interval (+ i 1) j))))
(define (enumerate-interval-k i j k)
  (if (> i j) nil (cons i (enumerate-interval-k (+ i k) j k))))
(enumerate-interval-k 1 10 2)
(enumerate-interval 1 10)
(accumulate append
            nil
            (map (lambda(i)
                   (map (lambda (j) (list i j))
                      (enumerate-interval 1 (- i 1))))
                 (enumerate-interval 1 5)))

(define (flatmap proc sequence)
  (accumulate append nil (map proc sequence)))

filter
(eq? (cons 1 2) (list 1 2))
(eqv? (list 1 2) (list 1 2))
(eq? (list 1 2) (list 1 2))
(equal? (list 1 2) (list 1 2))

(define (remove item sequence)
  (filter (lambda (x) (not (= x item))) sequence))
(define (permutations s)
  (if (null? s)
      (list nil)
      (flatmap (lambda (x)
                 (map (lambda (p) (cons x p))
                      (permutations (remove x s))))
               s)))
(permutations lst)
(length (permutations lst))

;; excersize 2.40
(define (unique-pairs n)
  (flatmap
   (lambda (i)
     (accumulate cons nil
                 (map (lambda (j) (cons j i))
                      (enumerate-interval 1 (- i 1)))))
   (enumerate-interval 1 n)))
(unique-pairs 4)

(list? (cons 2 nil)) ;#t
(list? (cons 2 3))   ;#f
(cons (list 1 2) (list 3 4)) ;((1 2) 3 4)

(define (and-all items)
  (cond ((null? items) #t)
        ((car items) (and-all (cdr items)))
        (else #f)))
(and-all (list #t #t #t))
(and-all (list #t #f #t))
(and-all (list #t #t #f))

(define x 11)
(define (prime? x)
  (if (= 2 x) #t
      (and-all (map (lambda (p) (< 0 (remainder x p)))
                (cons 2 (enumerate-interval-k 3 (/ x 2) 2))))))
(map (lambda (x) (cons x (prime? x))) (enumerate-interval 1 15))

(define n 6)
(define (prime-sum-pairs n)
  (filter (lambda (x) (prime? (+ (car x) (cdr x))))
          (unique-pairs n)))
(prime-sum-pairs 6)
(list-ref lst 0)


(define e '((a 1) (b 2) (c 3)))
(assq 'a e)
(list? (car e))
(list? (cons 1 1))
(define x (list (list 1 1) (list 2 2)))
(define y (list (cons 1 1) (cons 2 2)))
(assq 1 x)
(assq 1 y)

;; sicp exercise 2.42
;; 
(define (queens board-size)
  (define (safe? k positions)
    (let ((k-row (cdr (assq k positions))))
      (and-all (map
                  (lambda (i)
                    (let* ((position (assq i positions))
                          (col (car position))
                          (row (cdr position)))
                      (and (not (= row k-row))
                           (not (= (- k col) (- k-row row)))
                           (not (= (- col k) (- k-row row))))))
                  (enumerate-interval 1 (- k 1))))))
  (define empty-board ())
  (define (adjoin-position new-row k rest-of-queens)
    (if (null? rest-of-queens)
        (list (cons k new-row))
        (append rest-of-queens (list (cons k new-row)))))
  (define (queen-cols k)
    (if (= 0 k)
        (list empty-board)
        (filter
         (lambda (positions) (safe? k positions))
         (flatmap
          (lambda (rest-of-queens)
            (map (lambda (new-row)
                   (adjoin-position new-row k rest-of-queens))
                 (enumerate-interval 1 board-size)))
          (queen-cols (- k 1))))))
  (queen-cols board-size))
(car (queens 8))

(define two-queens (queens 2))
(safe? 2 (car two-queens))
(define positions (car two-queens))
(define k 2)
(define k-row 2)

(let* ((a 2) (b (* a a))) b)

(adjoin-position 1 1 empty-board)
(accumulate (lambda (x y)(adjoin-position x x y))
            empty-board (enumerate-interval 1 4))
(RESTART 1)
